//
//  YGridView.m
//  yuimall_Iphone
//
//  Created by Gang.Wang on 12-4-26.
//  Copyright (c) 2012年 yuike. All rights reserved.
//

#import "YGridView.h"
#import "header.h"


@interface YGridView (private)

- (void)createTiles;
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
- (CALayer *)layerForTouch:(UITouch *)touch;
- (int)frameIndexForTileIndex:(int)tileIndex;
- (int)indexOfClosestFrameToPoint:(CGPoint)point;
- (void)moveHeldTileToPoint:(CGPoint)location;
- (void)moveUnheldTilesAwayFromPoint:(CGPoint)location;
- (void)startTilesWiggling;
- (void)stopTilesWiggling;

-(void) initGestureRecognizer;

-(void) reAdjustTileCount;
-(void) createTilesAndReAdjustTileCount;



@end


@implementation YGridView
@synthesize delegate = delegate_;

@synthesize tileRows;
@synthesize tileColumns;
@synthesize tileCount;

@synthesize dataSource;

@synthesize tileFrameEx;
@synthesize tileForFrameEx;

-(void) dealloc
{  
    YRelease(proxy);
    
    // 这里会崩溃 需要跟一下
    YRelease(tileFrameEx)
    YRelease(tileForFrameEx)
    
    [super dealloc];
}
- (void) setDataSource:(id<YGridViewDelegateDataSource>)dataSourceValue
{
    dataSource = dataSourceValue;
    
     [self createTilesAndReAdjustTileCount];
}

-(void) privateInit
{
    if (self.bInited) {
        return;
    }
    
    [self initGestureRecognizer];

    self->tileHeight = 100;
    self->tileWidth = 100;
    self->tileMargin = 18;
    
    self.tileForFrameEx = [[[NSMutableArray alloc] initWithCapacity:self.tileCount] autorelease];
    self.tileFrameEx = [[[NSMutableArray alloc] initWithCapacity:self.tileCount] autorelease] ;
       
    self->proxy = [[YLayerDelegateProxy alloc] initWithView:self];
   

    
    [self reAdjustLayout];
    self.bInited = TRUE;
}

-(id) init
{
    self = [super init];
    if (self) {
        [self privateInit];
    }
    return self;
}


- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        [self privateInit];
    }
    return self;
}

#pragma mark -
#pragma mark - Private Method

-(void) createTilesAndReAdjustTileCount
{
    [self createTiles];
    [self reAdjustTileCount];
    
    CGFloat height = [self showNeedHeightByLastTile];
    DELEGATE_CALLBACK(girdViewShowNeedHeight:, NUMBER(height))
}

- (void) reAdjustTileCount
{
    self.tileCount = [self.tileForFrameEx count];
}

-(void) initGestureRecognizer
{
    UITapGestureRecognizer * singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(click:)];
    [self addGestureRecognizer:singleTap];
    [singleTap release];
    

    UILongPressGestureRecognizer * longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
    [self addGestureRecognizer:longPress];
    YRelease(longPress);

}

-(void) drawYTileLayerLayer: (CALayer*) layer inContext: (CGContextRef) context
{
    
    
    UIGraphicsPushContext(context);
    
    YTileLayer *tile = (YTileLayer *)layer;
    [tile draw];
    
    UIGraphicsPopContext();
    
    return;

//    UIGraphicsBeginImageContext(CGSizeMake(layer.frame.size.width * 2, layer.frame.size.height));
//    CGContextRef ctx = UIGraphicsGetCurrentContext();

}


- (void)createTiles 
{
    [self.tileForFrameEx removeAllObjects];
    [self.tileFrameEx removeAllObjects];
    int addTilesCount = 0;
    for (int row = 0; row < self.tileRows; ++row) {
        for (int col = 0; col < self.tileColumns; ++col) {
            if (addTilesCount >= self.tileCount) {
                return;
            }
            
            int index = (row * self.tileColumns) + col;
            
            CGRect frame = CGRectMake(self->tileMargin + col * (self->tileMargin + self->tileWidth),
                                      self->tileMargin + row * (self->tileMargin + self->tileHeight),
                                      self->tileWidth, self->tileHeight);
            
            frame.origin.x = (int) frame.origin.x + 0.5f;
            frame.origin.y = (int) frame.origin.y + 0.5f;
            frame.size.width = (int) frame.size.width + 0.5f;
            frame.size.height = (int) frame.size.height + 0.5f;
            
            [self.tileFrameEx addObject:[NSValue valueWithCGRect:frame]];
            
            YTileLayer *tile = [self.dataSource tileLayer:self withTileIndex:index];      
            tile.tileIndex = index;
            [self.tileForFrameEx addObject:tile];
            
            tile.frame = frame;
            tile.delegate = self->proxy;
            [self.layer addSublayer:tile];
            
            [tile setNeedsDisplay];
            addTilesCount++;
        }
    }
}



- (void)moveHeldTileToPoint:(CGPoint)location {
    float dx = location.x - touchStartLocation.x;
    float dy = location.y - touchStartLocation.y;
    CGPoint newPosition = CGPointMake(heldStartPosition.x + dx, heldStartPosition.y + dy);
    
    [CATransaction begin];
    [CATransaction setDisableActions:TRUE];
    heldTile.position = newPosition;
    [CATransaction commit];
}


- (void)moveUnheldTilesAwayFromPoint:(CGPoint)location {
    int frameIndex = [self indexOfClosestFrameToPoint:location];
    if (frameIndex != heldFrameIndex) {
        [CATransaction begin];
        
        if (frameIndex < heldFrameIndex) {
            for (int i = heldFrameIndex; i > frameIndex; --i) {
                YTileLayer *movingTile = [self.tileForFrameEx objectAtIndex:i -1];
                
                CGRect frameEx  = [(NSValue *)[self.tileFrameEx objectAtIndex:i] CGRectValue];
                movingTile.frame = frameEx;
                [self.tileForFrameEx replaceObjectAtIndex:i withObject:movingTile];
            }
        }
        else if (heldFrameIndex < frameIndex) {
            for (int i = heldFrameIndex; i < frameIndex; ++i) {
                YTileLayer *movingTile = [self.tileForFrameEx objectAtIndex:i + 1]; 
                CGRect frameEx  = [(NSValue *)[self.tileFrameEx objectAtIndex:i] CGRectValue];
                 movingTile.frame = frameEx;
                [self.tileForFrameEx replaceObjectAtIndex:i withObject:movingTile];

            }
        }
        heldFrameIndex = frameIndex;
        [self.tileForFrameEx replaceObjectAtIndex:heldFrameIndex withObject:heldTile];
        
        [CATransaction commit];
    }
}



- (CALayer *)layerForTouch:(UITouch *)touch {
    UIView *view = self;
    
    CGPoint location = [touch locationInView:view];
    location = [view convertPoint:location toView:nil];
    
    CALayer *hitPresentationLayer = [view.layer.presentationLayer hitTest:location];
    if (hitPresentationLayer) {
        return hitPresentationLayer.modelLayer;
    }
    
    return nil;
}


- (int)frameIndexForTileIndex:(int)tileIndex {
    for (int i = 0; i < self.tileCount; ++i) {
        YTileLayer * tile = [self.tileForFrameEx objectAtIndex:i];
        if (tile.tileIndex == tileIndex) {
            return i;
        }
    }
    return 0;
}


- (int)indexOfClosestFrameToPoint:(CGPoint)point {
    int index = 0;
    float minDist = FLT_MAX;
    for (int i = 0; i < self.tileCount; ++i) {
        CGRect frame = [(NSValue*)[self.tileFrameEx objectAtIndex:i] CGRectValue];
        
        float dx = point.x - CGRectGetMidX(frame);
        float dy = point.y - CGRectGetMidY(frame);
        
        float dist = (dx * dx) + (dy * dy);
        if (dist < minDist) {
            index = i;
            minDist = dist;
        }
    }
    return index;
}


- (void)startTilesWiggling {
    for (int i = 0; i < self.tileCount; ++i) {
        YTileLayer *tile = [self.tileForFrameEx objectAtIndex:i];
        if (tile != heldTile) {
            [tile startWiggling];
        }
    }
}


- (void)stopTilesWiggling {
    
    [self setAllTileCanEdit];
    NSMutableArray * tiles__ = [[NSMutableArray alloc] init];
    
    for (int i = 0; i < self.tileCount; ++i) 
    {
        YTileLayer *tile = [self.tileForFrameEx objectAtIndex:i];
        [tile stopWiggling];
        [tiles__ addObject:tile];
    }
    DELEGATE_CALLBACK(tileSequenceNumberChanged:, tiles__);    
    [tiles__ autorelease];
}

- (void) reAdjustTileLayouts
{
    [self.tileFrameEx removeAllObjects];
    
    int addTilesCount = 0;
    for (int row = 0; row < self.tileRows; ++row) {
        for (int col = 0; col < self.tileColumns; ++col) {
            if (addTilesCount >= self.tileCount) 
            {
                return;
            }
                        
            CGRect frame = CGRectMake(self->tileMargin + col * (self->tileMargin + self->tileWidth),
                                      self->tileMargin + row * (self->tileMargin + self->tileHeight),
                                      self->tileWidth, self->tileHeight);  
            
            frame.origin.x = (int) frame.origin.x + 0.5f;
            frame.origin.y = (int) frame.origin.y + 0.5f;
            frame.size.width = (int) frame.size.width + 0.5f;
            frame.size.height = (int) frame.size.height + 0.5f;
            
            [self.tileFrameEx addObject:[NSValue valueWithCGRect:frame]];
            
            YTileLayer *tile = [self.tileForFrameEx objectAtIndex:addTilesCount];   
            tile.tileIndex = addTilesCount;
            
            tile.frame = frame;
            
            [tile setNeedsDisplay];
            addTilesCount++;
        }
    }
}

- (void) closeTile:(NSString *) layerId
{
    if ([NSString isNilOrEmpty:layerId]) {
        return;
    }
    
    int layerIndexInArray = 0;

    for (YTileLayer * tile in self.tileForFrameEx) 
    {
        if ([layerId isEqualToString:tile.layerId]) 
        {                       
            DELEGATE_CALLBACK(willDeleteTile:, tile)            
            [tile removeFromSuperlayer];
            break;
        }
        layerIndexInArray++;
    }
    
    
    [self.tileForFrameEx removeObjectAtIndex:layerIndexInArray];
    [self.tileFrameEx removeObjectAtIndex:layerIndexInArray];
    self.tileCount--;
    
    [self reAdjustTileLayouts];
    
    CGFloat height = [self showNeedHeightByLastTile];
    DELEGATE_CALLBACK(girdViewShowNeedHeight:, NUMBER(height))
}

- (void) setAllTileEditStatus:(BOOL) edit
{
    for (YTileLayer * tile in self.tileForFrameEx) {
        if (edit) {
            [tile startWiggling];
        }
        else {
            [tile stopWiggling];
        }
    }
}

- (void) setAllTileCanNotEdit
{
    [self setAllTileEditStatus:FALSE];
}

- (void) setAllTileCanEdit
{
    [self setAllTileEditStatus:TRUE];
}

- (CGFloat) showNeedHeightByLastTile
{
    CGFloat height = 0.0f;
    YTileLayer * lastTile = [self.tileForFrameEx lastObject];
    height = lastTile.frame.origin.y + lastTile.frame.size.height + 70;
    
    return height;
}

#pragma - public
- (void) insterTileAtIndex:(YTileLayer *) tile index:(NSInteger) index
{
    if (!tile) 
    {
        return;
    }
    
    if (index < 0) 
    {
        return;
    }
    
    
    if (index > [self.tileForFrameEx count]) 
    {
        return;
    }
    
    [self.layer addSublayer:tile];
    tile.delegate = self->proxy;
    
    [self.tileForFrameEx insertObject:tile atIndex:index];
    self.tileCount++;
    
    if (self.tileColumns * self.tileRows < self.tileCount) {
        self.tileRows++;
    }
    
    [self reAdjustTileLayouts];    
    
    CGFloat height = [self showNeedHeightByLastTile];
    DELEGATE_CALLBACK(girdViewShowNeedHeight:, NUMBER(height))
}

- (void) removeTileWithIndex:(NSInteger) index
{
    if (index < 0) 
    {
        return;
    }
    
    
    if (index > [self.tileForFrameEx count]) 
    {
        return;
    }

    NSString * layerId = [(YTileLayer *)[self.tileForFrameEx objectAtIndex:index] layerId];
    [self closeTile:layerId];
    
}

- (BOOL) isALLTileEditing
{
    BOOL result = TRUE;
    
    for (YTileLayer * tile in self.tileForFrameEx) 
    {
        if (!tile.editStatus) 
        {
            result = FALSE;
        }
    }
    
    return result;
}

#pragma mark -
#pragma mark - UIGestureRecognizer

- (void) click:(UIGestureRecognizer *) gestureRecognizer
{    
    
    DebugLog(@"%d", gestureRecognizer.state);
    CALayer *layer=[self.layer hitTest:[gestureRecognizer locationInView:self]];    


    if (![layer isKindOfClass:[CALayerEx class]]) {
        // 这两句一定要放在 获取 layer 对象之后， 因为设置tile为正常状态的时候，会改变layer的层次
        [self stopTilesWiggling];
        [self setAllTileCanNotEdit];
        return;
    }
    
    if ([NSString isNilOrEmpty:layer.name] &&
        [[(CALayerEx *) layer layerId] endswith:@"/close"]) 
    {
        NSString * layerId = [(CALayerEx*) layer layerId];
        
        NSRange range;
        range.location = 0;
        range.length = [layerId length] - 6;  // "/close" lenght 
        layerId = [layerId substringWithRange:range];
        
        [self closeTile:layerId];
        return;
    }

        
    CALayer * superLayer = [layer superlayer];    
    
    if (![layer isKindOfClass:[YTileLayer class]] &&
        [superLayer isKindOfClass:[YTileLayer class]]) 
    {
        layer = superLayer;
    }
    
    if ([layer.name isEqualToString:@"YTileLayer"]) 
    {
        
        if ([(YTileLayer *)layer editStatus]) {
            // 这两句一定要放在 获取 layer 对象之后， 因为设置tile为正常状态的时候，会改变layer的层次
            [self stopTilesWiggling];
            [self setAllTileCanNotEdit];
            return;
        }
     
        DELEGATE_CALLBACK(clickWhichLayer:, layer);
        return;
    }
    
    
}

- (void) callDelegateHeldLocalPoint:(CGPoint ) point
{    
    if (self.delegate &&
        [self.delegate respondsToSelector:@selector(heldTileDidMoved:)]) {
        [self.delegate heldTileDidMoved:[NSValue valueWithCGPoint:point]];
    }
//    DELEGATE_CALLBACK(heldTileMoved2Boundary:, [NSValue valueWithCGPoint:point])
}

- (void) longPress:(UIGestureRecognizer *) gestureRecognizer
{    
    CALayer *hitLayer = [self.layer hitTest:[gestureRecognizer locationInView:self]];
    CALayer * superLayer = [hitLayer superlayer];
     switch ( gestureRecognizer.state )
    {
        case UIGestureRecognizerStateFailed:             
        case UIGestureRecognizerStatePossible:
        case UIGestureRecognizerStateCancelled:
            break;
            
        case UIGestureRecognizerStateEnded:
            if (heldTile) {
                [heldTile appearNormal];
                CGRect frame = [(NSValue*)[self.tileFrameEx objectAtIndex:heldFrameIndex] CGRectValue];
                heldTile.frame = frame;
                [heldTile setEditStatus:TRUE];
                [heldTile startWiggling];
                heldTile = nil;
            }
//            [self stopTilesWiggling];
            break;
            
         case UIGestureRecognizerStateBegan:
            
            if (![hitLayer isKindOfClass:[YTileLayer class]] &&
                  [superLayer isKindOfClass:[YTileLayer class]]) 
            {
                hitLayer = superLayer;
            }
            
            if ([hitLayer isKindOfClass:[YTileLayer class]]) {
                YTileLayer *tile = (YTileLayer*)hitLayer;
                heldTile = tile;
                
                touchStartLocation = [gestureRecognizer locationInView:self];
                heldStartPosition = tile.position;
                heldFrameIndex = [self frameIndexForTileIndex:tile.tileIndex];
                
                [tile moveToFront];
                [tile appearDraggable];
                [self startTilesWiggling];
            }

            break;
            
         case UIGestureRecognizerStateChanged:
            if (heldTile) {
                CGPoint location = [gestureRecognizer locationInView:self];
                [self moveHeldTileToPoint:location];
                [self moveUnheldTilesAwayFromPoint:location];
                [self callDelegateHeldLocalPoint:location];                
            }

            break;
        default:
            break;
    }
}

//#pragma mark -touches Method
//- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
//{
//     CALayer *layer = [self layerForTouch:[touches anyObject]];
//    if (![layer isKindOfClass:[YTileLayer class]] &&
//        [layer isKindOfClass:[YTileLayer class]]) 
//    {
//        [layer setBackgroundColor:RGBA(0, 0, 0, 0.5).CGColor];
//    }
//        
//     
//}
//
//- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
//{
//     CALayer *hitLayer = [self layerForTouch:[touches anyObject]];
//    //[hitLayer setBackgroundColor:RGBA(255, 255, 255, 0.0f).CGColor];
//}

@end
